/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package game;

import game.chips.*;
import java.io.PrintWriter;

import java.util.concurrent.*;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicIntegerArray;
import org.apache.log4j.Logger;

public class Player implements Runnable {
    private static final Logger log = Logger.getLogger("infofile");
    
    private Game game;

    private ExecutorService exec = Executors.newFixedThreadPool(10);
    private List<game.chips.Chip> chips;

    private int numPlayer;

    private volatile boolean turn;

    private volatile int countChips;
    private Color color;
    
    private PrintWriter out;

    public Player(Game game, Color color) {
        this.color = color;
        this.game = game;
        chips = new CopyOnWriteArrayList<game.chips.Chip>();
        
        if (color == Color.WHITE)
            numPlayer = 0;
        else if (color == Color.BLACK)
            numPlayer = 1;
        
        initChips();
        
    }
    
    public PrintWriter getPw() {
        return out;
    }

    public void run() {
        try {
            while (countChips != 0 && !game.isEnd()) {
                if (turn)
                    makeTurn();
                else 
                    try {
                    Thread.sleep(5);
                } catch (InterruptedException ex) {
                    
                }
            }
            for (int i = 0; i < chips.size(); i++) {
                chips.get(i).setOut();
            }
        } finally {
            exec.shutdownNow();
        }
    }

    private void makeTurn() {
        try {
            //while (!turn || game.isEnd())
            //    wait(10);

            int col, line;

            while (true) {
                col = new Random().nextInt(game.getSize());
                //log.debug(game + " pre col " + col);

                if (numPlayer == 0) {
                    if (game.getPlayers().get(1).emptyCol(col))
                        continue;
                } else {
                    if (game.getPlayers().get(0).emptyCol(col))
                        continue;
                }

                line = firstInCol(col);
                if (line != -1)
                    break;
            }
            
            //log.debug(game + "col = " + col + " line = " + line);
            
            for (game.chips.Chip chip : chips) {
                chip.setBeforeTurn();
                if (chip.getState().get(0) == col && chip.getState().get(1) == line && !chip.getOut()) {
                    chip.setTurn();
                    while (chip.getTurn()) {
                        Thread.sleep(10);
                    }
                } else {
                    chip.setAfterTurn(chip.getBeforeTurn());
                }
            }

            turn = false;
            game.checkGame();
            //game.paced();

        } catch (InterruptedException e) {
            exec.shutdownNow();
        }
    }

    public void updateChips() {
        int index = -1;
        for (int i = 0; i < chips.size(); i++) {
            chips.get(i).setState(chips.get(i).getAfterTurn());
            chips.get(i).setBeforeTurn();
            if (chips.get(i).getOut()) {
                index = i;
            }
        }
        if (index != -1) {
            int col = chips.get(index).getState().get(0);
            int row = chips.get(index).getState().get(1);
            for (game.chips.Chip chip : chips)
                if (col == chip.getState().get(0) && row != chip.getState().get(1))
                    chip.setFirst();
            chips.remove(index);
        }
    }

    private int firstInCol(int col) {
        SortedSet<Integer> set = new TreeSet<Integer>();
        for (game.chips.Chip chip : chips) {
            if (chip.getState().get(0) == col) {
                if (!chip.getOut())
                    set.add(chip.getState().get(1));
            }
        }
        if (numPlayer == 0) {
            return (set.isEmpty() ? -1 : set.last());
        } else {
            return (set.isEmpty() ? -1 : set.first());
        }
    }

    public boolean emptyCol(int col) {
        for (game.chips.Chip chip : chips) {
            if (chip.getState().get(0) == col)
                return false;
        }

        return true;
    }

    private synchronized void initChips() {
        for (int i = 0; i < Game.getSize(); i++) {
            for (int j = 0; j < Game.getChipLines(); j++) {
                chips.add(ChipsFactory.getInstance().getChip(color, this));
                countChips++;
            }
        }

        for (int x = 0; x < Game.getSize(); x++) {
            for (int y = 0; y < Game.getChipLines(); y++) {
                int tmp[] = {x, y + numPlayer * (Game.getSize() - Game.getChipLines())};
                AtomicIntegerArray coord = new AtomicIntegerArray(tmp);
                chips.get(y * Game.getSize() + x).setState(coord);
                if (tmp[1] == Game.getChipLines() - 1 || tmp[1] == Game.getSize() - Game.getChipLines())
                    chips.get(y * Game.getSize() + x).setFirst();
            }
        }

        for (game.chips.Chip chip : chips) {
            chip.setBeforeTurn();
            chip.setAfterTurn(chip.getBeforeTurn());
            exec.execute(chip);
        }
        
        game.startPlayer(this);
    }

    public void nextTurn() {
        turn = true;
    }

    public void endTurn() {
        turn = false;
    }

    public int getCountChips() {
        return countChips;
    }

    public List<game.chips.Chip> getChips() {
        return chips;
    }

    public int getNumPlayer() {
        return numPlayer;
    }

    public void chipKilled() {
        countChips--;
    }

    public String toString() {
        return ("Player#" + numPlayer);
    }
    
    public Game getGame() {
        return game;
    }
}
